﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using SteamFluentAPI.Infrastructure.Base;

namespace SteamFluentAPI.Infrastructure
{
    public static class SteamFluentAPIExtensions
    {
        /// <summary>
        /// Determines whether this property is tagged with SteamInterfaceAttribute
        /// </summary>
        /// <param name="info"></param>
        /// <returns></returns>
        public static bool IsInterface(this PropertyInfo info)
        {
            SteamInterfaceAttribute interfaceAtt = null;
            return info.IsSteamInterface(out interfaceAtt);
        }

        /// <summary>
        /// Determines whether this property is tagged with SteamInterfaceAttribute
        /// </summary>
        /// <param name="info"></param>
        /// <param name="interfaceAtt">Returns this attribute</param>
        /// <returns></returns>
        public static bool IsSteamInterface(this PropertyInfo info, out SteamInterfaceAttribute interfaceAtt)
        {
            SteamInterfaceAttribute tryInterfaceAtt = info.GetCustomAttribute<SteamInterfaceAttribute>();

            if (tryInterfaceAtt != null)
            {
                interfaceAtt = tryInterfaceAtt;
                return true;
            }

            interfaceAtt = null;
            return false;
        }

        /// <summary>
        /// Determines whether this property is tagged with SteamMethodAttribute
        /// </summary>
        /// <param name="info"></param>
        /// <returns></returns>
        public static bool IsSteamMethod(this PropertyInfo info)
        {
            SteamMethodAttribute methodAtt = null;
            return info.IsSteamMethod(out methodAtt);
        }

        /// <summary>
        /// Determines whether this property is tagged with SteamMethodAttribute
        /// </summary>
        /// <param name="info"></param>
        /// <param name="methodAtt">Returns this attribute</param>
        /// <returns></returns>
        public static bool IsSteamMethod(this PropertyInfo info, out SteamMethodAttribute methodAtt)
        {
            SteamMethodAttribute tryMethodAtt = info.GetCustomAttribute<SteamMethodAttribute>();

            if (tryMethodAtt != null)
            {
                methodAtt = tryMethodAtt;
                return true;
            }

            methodAtt = null;
            return false;
        }

        /// <summary>
        /// Determines whether this property is tagged with NotImplementedAttribute
        /// </summary>
        /// <param name="info"></param>
        /// <returns></returns>
        public static bool IsImplemented(this PropertyInfo info)
        {
            return (info.GetCustomAttribute<NotImplementedAttribute>() == null);
        }

        [Obsolete("Replaced by GetRequiredParameters")]
        public static bool HasRequiredParameters(this MethodInfo info)
        {
            string requiredParameter = string.Empty;
            return info.HasRequiredParameters(out requiredParameter);
        }

        [Obsolete("Replaced by GetRequiredParameters")]
        public static bool HasRequiredParameters(this MethodInfo info, out string requiredParameter)
        {
            RequiredParameterAttribute requiredAtt = info.GetCustomAttribute<RequiredParameterAttribute>();

            if (requiredAtt != null)
            {
                requiredParameter = requiredAtt.ParameterName;
                return true;
            }

            requiredParameter = string.Empty;
            return false;
        }

        /// <summary>
        /// Returns a list of required parameters in a SteamMethod
        /// </summary>
        /// <param name="infos"></param>
        /// <returns></returns>
        public static List<string> GetRequiredParameters(this SteamMethod method)
        {
            List<string> requiredParameters = new List<string>();

            foreach (MethodInfo parameter in method.GetType().GetMethods())
            {
                RequiredParameterAttribute requiredAtt = parameter.GetCustomAttribute<RequiredParameterAttribute>();

                if (requiredAtt != null)
                {
                    requiredParameters.Add(requiredAtt.ParameterName);
                }
            }

            return requiredParameters;
        }

        public static string ToDelimitedString<T>(this IEnumerable<T> source)
        {
            return ToDelimitedString(source, ',');
        }

        public static string ToDelimitedString<T>(this IEnumerable<T> source, char delimiter)
        {
            string delimitedString = "";
            foreach (T item in source)
            {
                delimitedString += item.ToString() + delimiter;
            }

            //remove last delimiter
            delimitedString = delimitedString.Remove(delimitedString.Length - 1, 1);
            return delimitedString;
        }

        /// <summary>
        /// Enumerates this IEnumerable source with action.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source"></param>
        /// <param name="action"></param>
        public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
        {
            if (source != null || source.Count() > 0)
            {
                foreach (T item in source)
                {
                    action(item);
                }
            }
        }
    }
}
